package com.common.utils;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Map;
import java.util.Set;

/**
 * @author gm
 * @description 反射工具类
 * @date 2020/1/7
 */
public class ReflectUtil {
    private static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy/MM/dd");

    /**
     * 当前方法的作用是将request中的参数封装到对象中
     */
    public static <T> T convertData(Map<String, String[]> map, Class<T> clazz) throws Exception {
        //HttpServletRequest re;
        //Map<String, String[]> map = re.getParameterMap();
        //最终的目的是将map中的数据封装到clazz对应的类型对象上面，然后返回
        T newInstance = clazz.newInstance();
        //解析参数
        //获取到每个参数的名字，然后将这个参数对应的值封装到这个对象上面的对应的属性上面
        //1要求 form表单中的参数的名字必须和对象上面的属性名一致
        //获取到所有参数的键值对，而且这个的键就是参数的名字，也就是是对象上面对应的属性名
        Set<Map.Entry<String, String[]>> entrySet = map.entrySet();

        for (Map.Entry<String, String[]> entry : entrySet) {
            //获取到key
            String key = entry.getKey();
            System.out.println("当前正在封装:" + key);
            //根据key去找刚才我们用于封装参数的对象上面的与key的值一样的属性名
            PropertyDescriptor descriptor = new PropertyDescriptor(key, clazz);
            if (descriptor != null) {
                //获取到set方法
                Method writeMethod = descriptor.getWriteMethod();
                //调用set方法，然后将这个key对应的值设置进去，那么就到了对象上面
                //entry.getValue() form 表单中传递过来的与key对应的具体值，我们需要设置给对象
                String[] value = entry.getValue();

                //为了保证参数的长度或者类型是匹配的，我们需要将form表单传递过来的数据 转换成为对象setter方法相对应的参数类型
                //获取setter的方法的参数类型

                Class<?>[] parameterTypes = writeMethod.getParameterTypes();

                //进行参数类型转换
                if (parameterTypes.length >= 1) {
                    //获取到参数的类型，是一个Class
                    Class<?> type = parameterTypes[0];
                    if (type == int.class || type == Integer.class) {
                        if (value == null || value.length != 1) {
                            throw new RuntimeException("参数:" + key + "的长度必须为1");
                        } else {
                            //[18,23,34]  int age =18;
                            int parseInt = Integer.parseInt(value[0]);
                            writeMethod.invoke(newInstance, parseInt);
                        }
                    } else if (type == String.class) {
                        if (value != null) {
                            writeMethod.invoke(newInstance, Arrays.toString(value).replace("[", "").replace("]", ""));
                        }
                    } else if (type == String[].class) {
                        //数组类型会抛出长度异常
                        //java反射规范中，数组参数的传递需要进行转换，转换为object[]
                        /*  String[] strings = new String[value.length];
                        for (int i = 0; i < value.length; i++) {
                            strings[i]=value[i];
                        }
                        writeMethod.invoke(newInstance,strings);*/
                        writeMethod.invoke(newInstance, new Object[]{value});
                    } else if (type == int[].class || type == Integer[].class) {
                        //writeMethod.invoke(newInstance,new Object[]{value});
                        int[] ints = new int[value.length];
                        for (int i = 0; i < value.length; i++) {
                            ints[i] = Integer.parseInt(value[i]);
                        }
                        //如果是在这里手动new的对象，可以不用再转换为object[]
                        writeMethod.invoke(newInstance, ints);
                    }
                }
            }
        }
        //返回带有数据的对象，也就是我们创建的对象
        return newInstance;
    }
}
